/*
 * Copyright (C) 2011, EADS France
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */

package xowl.interpreter.impl;

import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author Laurent WOUTERS
 */
public class ThreadContext {
    protected ThreadContext parent;
    protected xowl.lang.runtime.LexicalContext lexicalContext;
    protected Map<xowl.lang.actions.CodeVariable, xowl.lang.runtime.Upvalue> mapUpvalues;

    public ThreadContext getParent() { return parent; }

    public ThreadContext() {
        this.parent = null;
        this.lexicalContext = new xowl.lang.runtime.LexicalContext();
        this.mapUpvalues = new HashMap<xowl.lang.actions.CodeVariable, xowl.lang.runtime.Upvalue>();
    }
    public ThreadContext(ThreadContext parent) {
        this.parent = parent;
        this.lexicalContext = new xowl.lang.runtime.LexicalContext();
        this.mapUpvalues = new HashMap<xowl.lang.actions.CodeVariable, xowl.lang.runtime.Upvalue>();
    }
    public ThreadContext(xowl.lang.runtime.Closure closure) {
        this.parent = null;
        this.lexicalContext = closure.getContext();
        this.mapUpvalues = new HashMap<xowl.lang.actions.CodeVariable, xowl.lang.runtime.Upvalue>();
        for (xowl.lang.runtime.Upvalue up : lexicalContext.getAllUpvalues())
            this.mapUpvalues.put(up.getVariable(), up);
    }

    public boolean assign(xowl.lang.actions.CodeVariable var, xowl.lang.runtime.Value value) {
        if (!assign_Deep(var, value))
            assign_Final(var, value);
        return true;
    }
    protected boolean assign_Deep(xowl.lang.actions.CodeVariable var, xowl.lang.runtime.Value value) {
        if (parent != null)
            if (parent.assign_Deep(var, value))
                return true;
        if (mapUpvalues.containsKey(var)) {
            assign_Final(var, value);
            return true;
        }
        return false;
    }
    protected void assign_Final(xowl.lang.actions.CodeVariable var, xowl.lang.runtime.Value value) {
        xowl.lang.runtime.Upvalue upvalue = null;
        if (mapUpvalues.containsKey(var)) {
            upvalue = mapUpvalues.get(var);
        } else {
            upvalue = new xowl.lang.runtime.Upvalue();
            upvalue.setVariable(var);
            lexicalContext.addUpvalues(upvalue);
            mapUpvalues.put(var, upvalue);
        }
        upvalue.setValue(value);
    }

    public xowl.lang.runtime.Value get(xowl.lang.actions.CodeVariable var) {
        if (mapUpvalues.containsKey(var))
            return mapUpvalues.get(var).getValue();
        if (parent != null)
            return parent.get(var);
        return null;
    }

    public xowl.lang.runtime.LexicalContext getBounds() {
        xowl.lang.runtime.LexicalContext bounds = new xowl.lang.runtime.LexicalContext();
        ThreadContext current = this;
        while (current != null) {
            for (xowl.lang.runtime.Upvalue upvalue : current.lexicalContext.getAllUpvalues())
                bounds.addUpvalues(upvalue);
            current = current.parent;
        }
        return bounds;
    }
}
